package com.komon.object.request.bodyIO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.komon.util.CommonUtils;


/**
 *  Chunked-Body   = 	*chunk
                        last-chunk
                        trailer
                        CRLF
       chunk          = chunk-size [ chunk-extension ] CRLF
                        chunk-data CRLF
       chunk-size     = 1*HEX
       last-chunk     = 1*("0") [ chunk-extension ] CRLF
       chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
       chunk-ext-name = token
       chunk-ext-val  = token | quoted-string
       chunk-data     = chunk-size(OCTET)
       trailer        = *(entity-header CRLF)

 * @author timon.zhang
 *
 */
//TODO concurrent
public class ChunkedRequestInputStream extends HttpRequestBodyEncodingInputStream {
	private int chunk_offset;
	private int chunk_size;
	private enum parseStatus{
		CHUNK_SIZE, CHUNKDATA, TRAILER, END
	}
	private parseStatus status;
	
	public ChunkedRequestInputStream(InputStream socketInputStream) {
		super(socketInputStream);
	}

	/* (non-Javadoc)
	 * @see com.komon.object.HttpRequestBodyInputStream#read()
	 */
	@Override
	public int read() throws IOException {
		if (status.equals(parseStatus.CHUNK_SIZE)){
			char c = (char) in.read();
			StringBuffer sb = new StringBuffer();
			while(c != ' '){
				sb.append(c);
			}
			chunk_size = Integer.valueOf(sb.toString(), 16);
			//then we don't support chunk-ext-name now
			readNextCRLFLine(in);
			if (chunk_size <= 0) {
				status = parseStatus.TRAILER;
			} else{
				status = parseStatus.CHUNKDATA;
			}
		}
		
		 if (status.equals(parseStatus.CHUNKDATA)) {
			int result = in.read();
			if (result == -1){
				return -1;
			}
			//this is the end of current chunk, then ready to read next chunk size
			if (++chunk_offset >= chunk_size){
				readNextCRLFLine(in);
				status = parseStatus.CHUNK_SIZE;
			}
			return result;
		}
		 
		if (status.equals(parseStatus.TRAILER)) {
			//we don't support parse trailer now
			BufferedReader reader  = new BufferedReader(new InputStreamReader(in));
			String currentLine = reader.readLine();
			while(!CommonUtils.isCRLF(currentLine)){
				currentLine = reader.readLine();
			}
			status = parseStatus.END;
		}
		
		if (status.equals(parseStatus.END)) {
			return -1;
		}
		return -1;
	}

	
	private void readNextCRLFLine(InputStream inputStream) throws IOException {
		char c = '0';
		while ( true) {
			c = (char) inputStream.read();
			if (c == '\r'){
				c = (char) inputStream.read();
				if (c == '\n');{
					return ;
				}
			}
		}
	}
	
	@Override
	public void skipCurrentRequest() throws IOException {
		while(read() != -1){
			read();
		}
	}
}
